//
//  TBProcessChainTest.m
//  ocdemo
//
//  Created by JIENING ZHANG on 2020/2/25.
//  Copyright © 2020 JIENING ZHANG. All rights reserved.
//

#import "TBProcessChainTest.h"
#import "TBProcessNodeMC.h"
#import "TBProcessChainMC.h"

#import <Foundation/Foundation.h>

@interface TBProcessNode1 : TBProcessNodeMC
@end

@implementation TBProcessNode1
-(void) ready2work:(NSDictionary * _Nullable)startInfo {
    NSLog(@"TBProcessNode1, ready2work, thread:%@", [NSThread currentThread]);
    [self goSucc:@{}];
}
@end

@interface TBProcessNode2 : TBProcessNodeMC
@end

@implementation TBProcessNode2
-(void) ready2work:(NSDictionary * _Nullable)startInfo {
    NSLog(@"TBProcessNode2, ready2work, thread:%@", [NSThread currentThread]);
    [self goSucc:@{}];
}
@end

@interface TBProcessNode3 : TBProcessNodeMC
@end

@implementation TBProcessNode3
-(void) ready2work:(NSDictionary * _Nullable)startInfo {
    NSLog(@"TBProcessNode3, ready2work, thread:%@", [NSThread currentThread]);
    [self goSucc:@{}];
}
@end

@interface TBProcessNodeA : TBProcessNodeMC
@end

@implementation TBProcessNodeA
-(void) ready2work:(NSDictionary * _Nullable)startInfo {
    NSLog(@"TBProcessNodeA, ready2work, thread:%@", [NSThread currentThread]);
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.f * NSEC_PER_SEC)),
                   dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
                   ^{
        [self goSucc:@{}];
    });
}
@end

@interface TBProcessNodeB : TBProcessNodeMC
@end

@implementation TBProcessNodeB
-(void) ready2work:(NSDictionary * _Nullable)startInfo {
    NSLog(@"TBProcessNodeB, ready2work, thread:%@", [NSThread currentThread]);
    NSUInteger timets = (NSUInteger)([[NSDate new] timeIntervalSince1970]);
    if(0 == timets%2) {
        [self goDie:@{}];
    } else {
        [self goSucc:@{}];
    }
}
@end

@interface TBProcessNodeC : TBProcessNodeMC
@end

@implementation TBProcessNodeC
-(void) ready2work:(NSDictionary * _Nullable)startInfo {
    NSLog(@"TBProcessNodeC, ready2work, thread:%@", [NSThread currentThread]);
    [self goSucc:@{}];
}
@end

@interface TBProcessNodeD : TBProcessNodeMC
@end

@implementation TBProcessNodeD
-(void) ready2work:(NSDictionary * _Nullable)startInfo {
    NSLog(@"TBProcessNodeD, ready2work, thread:%@", [NSThread currentThread]);
    [self goSucc:@{}];
}
@end

@interface TBProcessNodeE : TBProcessNodeMC
@end

@implementation TBProcessNodeE
-(void) ready2work:(NSDictionary * _Nullable)startInfo {
    NSLog(@"TBProcessNodeE, ready2work, thread:%@", [NSThread currentThread]);
    [self goSucc:@{}];
}
@end

@interface TBProcessNodeF : TBProcessNodeMC
@end

@implementation TBProcessNodeF
-(void) ready2work:(NSDictionary * _Nullable)startInfo {
    NSLog(@"TBProcessNodeF, ready2work, thread:%@", [NSThread currentThread]);
    [self goSucc:@{}];
}
@end








static TBProcessChainMC *processChain;

@implementation TBProcessChainTest

+ (void)demoLogic {
    
    TBProcessNodeMC *node0 = [TBProcessNodeMC new]; node0.nodeName = @"n0";
    TBProcessNode1 *node1 = [TBProcessNode1 new]; node1.nodeName = @"n1";
    TBProcessNode2 *node2 = [TBProcessNode2 new]; node2.forceMainThread = YES; node2.nodeName = @"n2";
    TBProcessNode3 *node3 = [TBProcessNode3 new]; node3.nodeName = @"n3";
    
    TBProcessNodeA *nodeA = [TBProcessNodeA new]; nodeA.nodeName = @"nA";
    nodeA.forceMainThread = YES;
    //nodeA.timeOut4Process = 1.822f; // nodeA 执行时间约2秒，timeout>1.822 大概率看到 nodeA执行完早于 timeout。timeout<1.822 大概率看到 nodeA执行完晚于 timeout。
    nodeA.timeOut4Process = 1.9f;
    
    TBProcessNodeB *nodeB = [TBProcessNodeB new]; nodeB.forceMainThread = YES; nodeB.nodeName = @"nB";
    TBProcessNodeC *nodeC = [TBProcessNodeC new]; nodeC.nodeName = @"nC";
    TBProcessNodeD *nodeD = [TBProcessNodeD new]; nodeD.forceMainThread = YES; nodeD.nodeName = @"nD";
    TBProcessNodeE *nodeE = [TBProcessNodeE new]; nodeE.nodeName = @"nE";
    TBProcessNodeF *nodeF = [TBProcessNodeF new]; nodeF.nodeName = @"nF";

    
    
    processChain = [TBProcessChainMC new];
    
    /* 串行 node1 --> node2 --> nodeA --> nodeB --> nodeC --> nodeD --> nodeE --> nodeF（end）
     
    [processChain addNodeSequeceIntoChain:@[node1, node2, nodeA, nodeB, nodeC, nodeD, nodeE, nodeF] isStrongRelation:YES];
    //*/
    
    
    //* 串并行 node1 --> node2 -->  nodeC -->  nodeE --> nodeF（end）
    //              ↘ nodeA -->  nodeD _______↗
    //              ↘ nodeB __________________↗
     
    [processChain addNodeSequeceIntoChain:@[node1, node2, nodeC, nodeE, nodeF] isStrongRelation:YES];
    [processChain addNodeSequeceIntoChain:@[node1, nodeA, nodeD, nodeE] isStrongRelation:YES];
    [processChain addNodeSequeceIntoChain:@[node1, nodeB, nodeE] isStrongRelation:NO];
    //*/
    
    /* 并行  node1 -->  node0 --------> nodeF（end）
    //              ↘   node2 ________↗
    //              ↘   nodeA ________↗
    //              ↘   nodeB __weak__↗
    //              ↘   nodeC ________↗
    //              ↘   nodeD ________↗
    //              ↘   nodeE ________↗
     
    [processChain addNodeIntoChain:node1 subNodeList:@[node0, node2, nodeA, nodeB, nodeC, nodeD, nodeE] isStrongRelation:YES];
    [processChain addNodeListIntoChain:@[node0, node2, nodeA, nodeB, nodeC, nodeD, nodeE] subNode:nodeF isStrongRelation:YES];
    [processChain addNodeIntoChain:nodeB subNode:nodeF isStrongRelation:NO];
    //*/
    
    
    /* 处理链中有环
    //     node1 --> node2 -->  nodeC -->   nodeE --> nodeF（end）
    //           --↘  nodeA -->  nodeD _____↗  |
    //           --↘  nodeB _____↗             |
    //                  ↑                      |
    //                  ↑______________________|
     
    [processChain addNodeSequeceIntoChain:@[node1, node2, nodeC, nodeE, nodeF] isStrongRelation:YES];
    [processChain addNodeSequeceIntoChain:@[node1, nodeA, nodeD, nodeE] isStrongRelation:YES];
    [processChain addNodeSequeceIntoChain:@[node1, nodeB, nodeD] isStrongRelation:YES];
    [processChain addNodeIntoChain:nodeE subNode:nodeB isStrongRelation:YES];
    //*/
    
    /* 起始节点不唯一
    //                                 nodeB ---↘
    // node1 --> node2 -->  nodeC -->  nodeE --> nodeF（end）
    //            ↘  nodeA -->  nodeD _____↗
    [processChain addNodeSequeceIntoChain:@[node1, node2, nodeC, nodeE, nodeF] isStrongRelation:YES];
    [processChain addNodeSequeceIntoChain:@[node1, nodeA, nodeD, nodeE] isStrongRelation:YES];
    [processChain addNodeIntoChain:nodeB subNode:nodeF isStrongRelation:YES];
    //*/
    
    /* 从处理链结束节点遍历得到的节点数组 和 处理链节点数组 不全等
    // nodeA --> nodeB
    // node1 --> node2 -->  nodeC -->  nodeE --> nodeF（end）
    //       --↘ nodeD _____↗
    [processChain addNodeSequeceIntoChain:@[node1, node2, nodeC, nodeE, nodeF] isStrongRelation:YES];
    [processChain addNodeSequeceIntoChain:@[node1, nodeD, nodeC] isStrongRelation:YES];
    [processChain addNodeIntoChain:nodeA subNode:nodeB isStrongRelation:YES];
    //*/
    
    /* 从处理链结束节点遍历得到的起始节点 和 处理链起始起点 不match
    // nodeC --> node2 --> nodeA --> nodeB --> node1(start) --> nodeD --> nodeE --> nodeF（end）
    [processChain addNodeSequeceIntoChain:@[ nodeC, node2, nodeA, nodeB, node1, nodeD, nodeE, nodeF] isStrongRelation:YES];
    //*/
    
    
    /* 从处理链结束节点遍历得到的节点数组 和 处理链节点数组 数量相同 但不全等
    //      node1 -->  nodeA --> nodeB --> nodeC --> nodeD --> nodeE --> nodeF（end）
    //                                                     --↘ node2 ____↗
    //      node3
    [processChain addNodeSequeceIntoChain:@[node1, nodeA, nodeB, nodeC, nodeD, nodeE, nodeF] isStrongRelation:YES];
    
    // addNodeIntoChain 是处理链不公开的方法，coder自行调用有出错风险
    if([processChain respondsToSelector:@selector(addNodeIntoChain:)]){
        [processChain performSelector:@selector(addNodeIntoChain:) withObject:node3];
    }
    
    // node自己确实有添加前置节点的方法，但是不建议coder调用，是给chain准备的，coder自行调用有出错风险
    [nodeF addPreNode:node2 preStrong:YES];
    [node2 addPreNode:nodeD preStrong:YES];
    //*/
        
    [processChain setKeyProcessNode:@[nodeA, nodeC, nodeD, nodeE, nodeF]];
    
    processChain.succBlock = ^(NSDictionary * _Nullable succInfo) {
        NSLog(@"processChain succBlock, succInfo %@, thread: %@", succInfo, [NSThread currentThread]);
    };
    
    processChain.failBlock = ^(NSDictionary * _Nullable failInfo) {
        NSLog(@"processChain failBlock, failInfo %@, thread: %@", failInfo, [NSThread currentThread]);
    };
    
    processChain.timeOut4Process = 2.086f;
    processChain.blockRunInMainThread = YES;
    
    [processChain setLogable:YES];
    
    processChain.makeChainImageWhenEnd = YES;
    
    // 如不设置将报错
    [processChain setFinishNode:nodeF];
    
    // processChain 的 节点数组的第一个节点作为 起始节点
    [processChain startWithNode:node1];
    
}

@end
